﻿#include <stdio.h>

//int main()
//{
//	int n = 10;
//	//创建指针变量
//	char* pc = (char*)&n;
//	int* pi = &n;
//
//	printf("%d\n", (int)&n);
//	printf("%d\n", (int)pc);
//	printf("%d\n", (int)pi);
//	printf("%d\n", *pc);
//	printf("%d\n", *pi);
//
//	printf("\npi + 1 = %d\n", (int)(pi + 1));//往后寻址4bytes
//	printf("pc + 1 = %d\n", (int)(pc + 1));//往后寻址1byte
//
//	printf("\n*pc + 1 = %d\n", *pc + 1);
//	printf("*pi + 10 = %d\n", *pi + 10);
//
//	*pi = 0;//n=0
//	printf("\n%d", *pi);
//
//
//	return 0;
//}

//const修饰指针变量
//int main()
//{
//	int n = 0;
//	int m = 1;
//	//const在*左边,限制*ptr
//	const int* ptr = &n;//int const* ptr = &n;
//	*ptr = 1;//error
//	int* ptr = &m;
//	
//	//const在*右边，限制ptr
//	int* const ptr = &n;
//	*ptr = 12;
//	ptr = &m;//error
//
//	return 0;
//}



//+-整数访问数组
//int main()
//{
//	int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
//	int* ptr = arr;//&arr[0]
//	
//	for (size_t i = 0; i < 10; i++)
//	{
//		printf("%d ", *(ptr + i));
//	}
//	ptr = &arr[5];//取第六位地址
//	printf("\n%d\n", *ptr);
//
//	ptr -= 2;//退回到第四位
//	printf("%d\n", *ptr);
//
//	return 0;
//}

//模拟strlen函数
//size_t my_strlen(char* s);
//int main()
//{
//	char str[1024];
//	size_t size = my_strlen(gets(str));
//	printf("%d\n", size);
//	return 0;
//}
//size_t my_strlen(char* s)
//{
//	char* start = s;
//	//统计'\0'前出现的字符串长度
//	while (*s != '\0')	s++;
//	return s - start;//指针 - 指针  地址 - 地址
//}

//野指针成因
//int main()
//{
//	int* ptr;
//	*ptr = 1;//非法访问内存
//}
// 
//越界访问
//int main()
//{
//	int arr[5] = { 0 };
//	//1 1 1 1 1 1 1 1 1 1
//	int i = 0;
//	int* p = arr;
//	for (i = 0; i < 10; i++)
//	{
//		*p = 1;
//		p++;
//	}
//	return 0;
//}
// 
//指向已释放的空间
//int* test()
//{
//	int a = 10;
//	//...
//	return &a;
//}
////a已经销毁
//int main()
//{
//	int*p = test();//p接受了a的地址，野指针
//	printf("%d\n", *p);
//	return 0;
//}

//assert断言
//#define NDEBUG
//#include <assert.h>
//
//int main()
//{
//	int a = 10;
//	int* p = &a;
//	//....
//	p = NULL;
//	int b = 5;
//	assert(p != NULL);
//	
//	printf("%d\n", *p);
//	return 0;
//}

////传值调用
//void Switch(int a, int b);
//int main()
//{
//	int x, y;
//	scanf_s("%d %d", &x, &y);
//	printf("before switching:x=%d y=%d\n", x, y);
//	Switch(x, y);
//	printf("after switching:x=%d y=%d\n", x, y);
//	return 0;
//}
//void Switch(int a, int b)
//{
//	int tmp = a;
//	a = b;
//	b = tmp;
//}
//
////传址调用
//void Switch(int* a, int* b);
//int main()
//{
//	int x, y;
//	scanf_s("%d %d", &x, &y);
//	printf("before switching:x=%d y=%d\n", x, y);
//	Switch(&x, &y);
//	printf("after switching:x=%d y=%d\n", x, y);
//	return 0;
//}
//void Switch(int* a, int* b)
//{
//	int tmp = *a;
//	*a = *b;
//	*b = tmp;
//}

//数组名的理解
//int main()
//{
//	int arr[5] = { 0,1,2,3,4 };
//
//	printf("&arr[0] = %p\n", &arr[0]);
//	printf("&arr[0] + 1 = %p\n", &arr[0] + 1);
//	printf("arr = %p\n", arr);
//	printf("arr + 1 = % p\n", arr + 1);
//	printf("&arr = %p\n", &arr);
//	printf("&arr + 1 = %p\n", &arr +1);
//
//	return 0;
//}

//一维数组传参本质
//void test(int arr[], size_t size);
//
//int main()
//{
//	int arr[5] = { 1,2,3,4,5 };
//	size_t sz = sizeof(arr) / sizeof(int);
//	test(arr,sz);
//	return 0;
//}
//void test(int arr[], size_t size)
//{
//	for (size_t i = 0; i < size; i++)
//	{
//		printf("%d ", arr[i]);
//	}
//}
////其实是一样的
//void test(int* arr, size_t size);
//int main()
//{
//	int arr[5] = { 1,2,3,4,5 };
//	size_t sz = sizeof(arr) / sizeof(int);
//	test(arr, sz);
//	return 0;
//}
//void test(int* arr, size_t size)
//{
//	for (size_t i = 0; i < size; i++)
//	{
//		printf("%d ", arr[i]);
//	}
//}

//冒泡排序
//#include <stdbool.h>
//void bubble_sort(int* arr, size_t size);
//int main()
//{
//	int arr_test[10] = { 8,3,2,1,0,9,6,7,5,4 };
//	size_t sz = sizeof(arr_test) / sizeof(int);
//	bubble_sort(&arr_test, sz);
//	for (size_t i = 0; i < sz; i++)
//	{
//		printf("%d ", arr_test[i]);
//	}
//	return 0;
//}
//void bubble_sort(int* arr, size_t size)
//{
//	for (size_t i = 0; i < size - 1; i++)//两两排序，有size个元素，则至少有size - 1趟
//	{
//		bool flag = 1;//假设这一趟已经有序
//		for (size_t j = 0; j < size - 1 - i; j++)//排序完成的元素无需作比较，逐次往后比较
//		{
//			if (arr[j] > arr[j + 1])//顺序，如果降序则改为<
//			{
//				flag = 0;//发生了交换，说明无序
//				int tmp = arr[j];//创建第三个变量方便排序
//				arr[j] = arr[j + 1];
//				arr[j + 1] = tmp;//升序完成
//			}
//		}
//		if (flag) break;//未交换说明有序，直接跳出循环！
//	}
//}

////选择排序
//#include <stdbool.h>
//void select_sort(int* arr, size_t size);
//int main()
//{
//		int arr_test[10] = { 8,3,2,1,0,9,6,7,5,4 };
//		size_t sz = sizeof(arr_test) / sizeof(int);
//		select_sort(&arr_test, sz);
//		for (size_t i = 0; i < sz; i++)
//		{
//			printf("%d ", arr_test[i]);
//		}
//		return 0;
//	return 0;
//}
//
//void select_sort(int* arr, size_t size)
//{
//	for (size_t i = 0; i < size - 1; i++)//有size个元素，则只少有size - 1趟
//	{
//		bool flag = 1;//假设这一趟已经有序
//		for (size_t j = i + 1; j < size; j++)//每一轮前面的元素都要和后面所有元素比较，比到最后一个
//		{
//			if (arr[i] > arr[j])
//			{
//				flag = 0;//发生交换
//				int tmp = arr[i];
//				arr[i] = arr[j];
//				arr[j] = tmp;
//			}
//		}
//		if (flag) break;
//	}
//}

//多级指针——套娃

//int main()
//{
//	int a = 10;
//	int* ptr_a = &a;//一级指针
//	int** ptr_a_a = &ptr_a;//二级指针
//	int*** ptr_a_a_a = &ptr_a_a;//三级指针
//
//	***ptr_a_a_a = 40;
//	//ptr_a_a_a存着ptr_a_a的地址,ptr_a_a存着ptr_a的地址,ptr_a存着a的地址,一层层指向
//	//*ptr_a_a_a等价于ptr_a_a  **ptr_a_a_a等价于ptr_a  ***ptr_a_a_a等价于*ptr_a 即a
//	printf("%d\n", ***ptr_a_a_a);
//	printf("%p\n", **ptr_a_a_a);
//	printf("%p\n", *ptr_a_a_a);
//
//}

//数组指针
/*
	存放指针的数组
	每个元素都是地址
	又可以指向一块区域
	int* arr[3];
*/

//模拟二维数组

//int main()
//{
//	int arr1[] = { 0,1,2,3,4 };
//	int arr2[] = { 1,2,3,4,5 };
//	int arr3[] = { 2,3,4,5,6 };
//	//数组名是数组首元素的地址，类型是int*，就可以存放在ptr_arr数组中
//	int* ptr_arr[3] = { arr1, arr2, arr3 };
//	for (size_t i = 0; i < 3; i++)
//	{
//		for (size_t j = 0; j < 5; j++)
//		{
//			printf("%d ", ptr_arr[i][j]);
//		}
//		printf("\n");
//	}
//	return 0;
//}

//字符指针
//可以把字符串想象成字符数组，但是这个数组不能修改
//字符常量字符串出现在表达式中，它的值是首字符的地址
//int main()
//{
//	const char* pc = "abcdef";
//	printf("%c\n", "abcdef"[3]);
//	printf("%c\n", pc[3]);
//
//	return 0;
//}

//int main()
//{
//	char str1[] = "hello CS.";
//	char str2[] = "hello CS.";
//
//	char* str3 = "hello CS.";
//	char* str4 = "hello CS.";
//
//	if (str1 == str2) printf("same\n");
//	else printf("not same\n");
//
//	puts("********");
//	if (str3 == str4) printf("same\n");
//	else printf("not same\n");
//
//	return 0;
//
//	/*
//		not same
//		********
//		* same
//	*/
//}

//数组指针
//int main()
//{
//	int arr[10] = { 0,1,2,3,4,5,6,7,8,9 };
//	////指针访问数组
//	int (*ptr)[10] = &arr;//ptr指向10个整形元素的数组
//	//printf("%p\n", arr);//数组首地址
//	//printf("%p\n", arr + 1);//首地址+1
//
//	//printf("%p\n", ptr);//首地址
//	//printf("%p\n", ptr + 1);//首地址+40
//	for (size_t i = 0; i < 10; i++)
//	{
//		printf("%d ", (*ptr)[i]);//*(*ptr + i)
//		/*
//			ptr == &arr
//			(*ptr) == *(&arr) == arr
//		*/
//	}
//
//	return 0;
//}

//二维数组传参本质——传递第一行一维数组的地址
//void Print(int (*arr)[5], int r, int c);
//
//int main()
//{
//	int arr[3][5] = { {0,1,2,3,4}, {1,2,3,4,5}, {2,3,4,5,6} };
//	Print(arr, 3, 5);
//	return 0;
//}
//void Print(int (*arr)[5], int r, int c)
//{
//	for (size_t i = 0; i < r; i++)
//	{
//		for (size_t j = 0; j < c; j++)
//		{
//			printf("%d ", *(*(arr + i) + j));
//		}
//		printf("\n");
//	}
//}

//函数指针

//函数也存在地址
//int test(int a, int b);
//
//int main()
//{
//	int x = 3;
//	int y = 9;
//	printf("%p\n",test);
//	printf("%p\n", &test);
//	return 0;
//}
//int test(int a, int b)
//{
//	return a + b;
//}

/*
    //函数指针的创建
	int (*ptr_test) (int a, int b); 
	int是指向函数的类型
	ptr_test是指针变量名
	(int a, int b)指针指向函数的参数类型与个数
*/

////通过函数指针调⽤指针指向的函数
//
//int Add(int a, int b)
//{
//	return a + b;
//}
//int main()
//{
//	int (*ptr_Add)(int a, int b) = Add;
//
//	printf("%d\n", ptr_Add(5, 8));
//	printf("%d\n", (*ptr_Add)(5, 8));
//
//	return 0;
//}

//void(*)(int) signal(int, void(*)(int));